package com.ygqh.baby.service.impl;

import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.util.StringUtil;
import com.ygqh.baby.ao.*;
import com.ygqh.baby.mapper.YgBmdismMapper;
import com.ygqh.baby.model.BmdismLadderModel;
import com.ygqh.baby.model.BmdismModel;
import com.ygqh.baby.model.YgShoppingCarModel;
import com.ygqh.baby.po.YgBmdism;
import com.ygqh.baby.po.YgBmdismExample;
import com.ygqh.baby.po.YgBmdismExample.Criteria;
import com.ygqh.baby.po.YgProduct;
import com.ygqh.baby.redis.RedisDao;
import com.ygqh.baby.service.YgBmdismService;
import com.ygqh.baby.service.YgShoppingCarService;
import com.ygqh.baby.utils.JsonUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Transaction;

import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

@Service
public class YgBmdismServiceImpl implements YgBmdismService {

    @Autowired
    private YgBmdismMapper ygBmdismMapper;
    @Autowired
    private YgShoppingCarService ygShoppingCarService;
    @Autowired
    private RedisDao redisDao;
    private final static String KEY = "BMDISM_KEY";

    @Override
    public List<YgBmdism> find(JobStatus jobStatus) {
        YgBmdismExample example = new YgBmdismExample();
        Criteria criteria = example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
        if (jobStatus != null) {
            Date date = new Date();
            if (jobStatus.equals(JobStatus.UnStart)) {
                criteria.andStartTimeGreaterThan(date);
            } else if (jobStatus.equals(JobStatus.Running)) {
                criteria.andStartTimeLessThanOrEqualTo(date).andEndTimeGreaterThan(date);
            } else {
                criteria.andEndTimeLessThanOrEqualTo(date);
            }
        }
        return ygBmdismMapper.selectByExample(example);
    }

    @Override
    public int findCount(JobStatus jobStatus) {
        YgBmdismExample example = new YgBmdismExample();
        Criteria criteria = example.createCriteria().andStatusEqualTo(DataStatus.Valid.name());
        if (jobStatus != null) {
            Date date = new Date();
            if (jobStatus.equals(JobStatus.UnStart)) {
                criteria.andStartTimeGreaterThan(date);
            } else if (jobStatus.equals(JobStatus.UnStart)) {
                criteria.andStartTimeLessThanOrEqualTo(date).andEndTimeGreaterThan(date);
            } else {
                criteria.andEndTimeLessThanOrEqualTo(date);
            }
        }
        return ygBmdismMapper.countByExample(example);
    }

    @Override
    public YgBmdism findById(Long id) {
        return ygBmdismMapper.selectByPrimaryKey(id);
    }

    @Override
    public int save(YgBmdism ygBmdism) {
        return ygBmdismMapper.insertSelective(ygBmdism);
    }

    @Override
    public int update(YgBmdism ygBmdism) {
        return ygBmdismMapper.updateByPrimaryKeySelective(ygBmdism);
    }

    @Override
    public ResultSet<YgBmdism> search(QueryInfo queryInfo, String title, Date startDate, Date endDate, JobStatus jobStatus, String q) {
        String status = jobStatus != null ? jobStatus.name() : null;
        List<YgBmdism> list = ygBmdismMapper.selectSuper(queryInfo, title, startDate, endDate, status, q);
        int count = ygBmdismMapper.countSuper(title, startDate, endDate, status, q);
        ResultSet<YgBmdism> resultSet = new ResultSet<YgBmdism>(count, list);
        return resultSet;
    }

    @Override
    public int deleteSoft(Long[] ids) {
        Assert.notEmpty(ids);
        YgBmdismExample example = new YgBmdismExample();
        example.createCriteria().andIdIn(Arrays.asList(ids));
        YgBmdism record = new YgBmdism();
        record.setStatus(DataStatus.Delete);

        return ygBmdismMapper.updateByExampleSelective(record, example);
    }

    @Override
    public int deleteSoft(Long id) {
        return this.deleteSoft(new Long[]{id});
    }

    @Override
    public int saveOrUpdate(YgBmdism ygBmdism) {
        int r = 0;
        if (ygBmdism.getId() != null) {
            r = this.update(ygBmdism);
        } else {
            r = this.save(ygBmdism);
        }
        return r;
    }

    @Override
    public List<YgProduct> findProductByBmdism(QueryInfo queryInfo, Long bmdismId, String productName) {
        return ygBmdismMapper.selectProductByBmdism(queryInfo, bmdismId, productName);
    }

    @SuppressWarnings({"unchecked", "static-access"})
    @Override
    public String addToRedis(YgBmdism ygBmdism) {

        long millis = System.currentTimeMillis();

        redisDao.watch(KEY);
        String result = redisDao.get(KEY);
        List<BmdismModel> list = null;
        if (StringUtil.isNotBlank(result)) {
            list = JSON.parseArray(result, BmdismModel.class);
        } else {
            list = new ArrayList<BmdismModel>();
        }
        BmdismModel cloneModel = ygBmdism.cloneModel();
        // 已过期
        list.removeIf(next -> millis > next.getEndTime().getTime() || next.getId().equals(cloneModel.getId()));
        list.add(cloneModel);
        Transaction tx = redisDao.multi();
        String json = JsonUtils.toJson(list);
        tx.set(KEY, json);
        tx.exec();
        return JsonUtils.toJson(json);
    }

    @Override
    public List<BmdismModel> findByProductIds(Long... productIds) {
        String result = redisDao.get(KEY);
        List<BmdismModel> list;
        List<BmdismModel> resutList = new ArrayList<BmdismModel>();
        if (StringUtil.isNotBlank(result)) {
            list = JSON.parseArray(result, BmdismModel.class);
        } else {
            list = new ArrayList<>();
        }
        for (Long pid : productIds) {
            for (BmdismModel bmdismModel : list) {
                if (!bmdismModel.isValid()) {
                    continue;
                }
                String[] ids = bmdismModel.getProductIds().split(",");
                List<String> asList = Arrays.asList(ids);
                bmdismModel.setProductIdList(asList);
                if (asList.contains(pid.toString())) {
                    if (!resutList.contains(bmdismModel)) {
                        resutList.add(bmdismModel);
                    }
                }
            }
        }

        return resutList.stream().sorted(Comparator.comparingInt(BmdismModel::getBuyCount)).collect(Collectors.toList());
    }

    private BmdismModel getBest(List<BmdismModel> list, Long buyCount) {
        BmdismModel model = null;
        for (BmdismModel m : list) {
            if (buyCount >= m.getBuyCount()) {
                model = m;
            }
        }
        return model;
    }

    @Override
    public void getBestBmdism(List<YgShoppingCarModel> carList) {
        if (!CollectionUtils.isEmpty(carList)) {

            Map<Long, List<YgShoppingCarModel>> map = ygShoppingCarService.sortCarMapV2(carList, carList.get(0).getUserId());

            for (Entry<Long, List<YgShoppingCarModel>> e : map.entrySet()) {
                // 多买多则商品
                if (e.getKey() < 0) {
                    List<YgShoppingCarModel> list = e.getValue();
                    Long buyCount = list.stream().map(YgShoppingCarModel::getQuantity).reduce(0L, (a, b) -> (a + b));
                    List<BmdismModel> bmdisms = this.findByProductIds(list.get(0).getProductId());

                    BmdismModel best = this.getBest(bmdisms, buyCount);
                    if (best != null) {
                        list.forEach(car -> {
                            car.setSalesType(PromotionType.Bmdism);
                            car.setPromotionPrice(car.getRealSalesPrice().multiply(new BigDecimal(best.getDisCount().toString())));
                            car.setRealSalesPrice(car.getPromotionPrice());
                            car.setVipPrice(car.getVipPrice().multiply(new BigDecimal(best.getDisCount().toString())));
                        });

                    }
                }
            }

        }
    }

    @Override
    public Message addBmdism(YgBmdism ygBmdism) {
        String[] ids = ygBmdism.getProductIds().split(",");
        Long[] priductIds = (Long[]) ConvertUtils.convert(ids, Long.class);
        List<BmdismModel> list = this.findByProductIds(priductIds);
        if (!CollectionUtils.isEmpty(list)) {
            for (BmdismModel m : list) {
                if (m.isValid() && ygBmdism.getStartTime().getTime() < m.getEndTime().getTime() && !m.getId().equals(ygBmdism.getId())) {
                    if (m.getBuyCount() == ygBmdism.getBuyCount()) {
                        return Message.error("同一梯度活动，每个商品只能参与一个", null);
                    }
                    if (!m.getProductIds().equals(ygBmdism.getProductIds())) {
                        return Message.error("多梯度活动，商品需一致", null);
                    }
                }
            }
        }
        int i = this.saveOrUpdate(ygBmdism);
        if (i > 0) {
            this.addToRedis(ygBmdism);
        }
        return Message.success(null);
    }

    /**
     * 该方法曲线救国了，
     * 解决方案  建议方案一
     * 1、调整运营后台 多买多折逻辑（增加多阶梯明细表）
     * 2、通过数据库关联查询 考虑到下单流程需要加缓存 编辑多买多折是需重置缓存
     *
     * @param productIds 商品id
     * @return List<BmdismLadderModel>
     */
    @Override
    public List<BmdismLadderModel> findBmdismListWithLadderByProductIds(Long... productIds) {
        List<BmdismLadderModel> resultList = new ArrayList<>();
        List<Long> bmdismIdList = new ArrayList<>();

        String result = redisDao.get(KEY);
        List<BmdismModel> list;
        if (StringUtil.isNotBlank(result)) {
            list = JSON.parseArray(result, BmdismModel.class);
        } else {
            list = new ArrayList<>();
        }
        for (Long pid : productIds) {
            List<BmdismModel> subList = new ArrayList<>();
            for (BmdismModel bmdismModel : list) {
                if (!bmdismModel.isValid()) {
                    continue;
                }
                List<String> asList = Arrays.asList(bmdismModel.getProductIds().split(","));
                bmdismModel.setProductIdList(asList);
                if (asList.contains(pid.toString())) {
                    if (!subList.contains(bmdismModel)) {
                        subList.add(bmdismModel);
                    }
                }
            }
            if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(subList)) {
                BmdismModel model = subList.stream().min(Comparator.comparingInt(BmdismModel::getBuyCount)).get();
                if (bmdismIdList.contains(model.getId())) {
                    continue;
                }
                bmdismIdList.add(model.getId());
                BmdismLadderModel bmdismLadderModel = new BmdismLadderModel();
                bmdismLadderModel.setId(model.getId());
                bmdismLadderModel.setStartTime(model.getStartTime());
                bmdismLadderModel.setEndTime(model.getEndTime());
                bmdismLadderModel.setProductIdList(model.getProductIdList());

                List<BmdismLadderModel.BmdismLadder> ladderList = new ArrayList<>();
                subList.forEach(item -> ladderList.add(bmdismLadderModel.new BmdismLadder(item.getId(), item.getBuyCount(), item.getDisCount())));

                bmdismLadderModel.setLadderList(ladderList);
                resultList.add(bmdismLadderModel);
            }
        }
        return resultList;
    }

}
